//-----------------------------------------------------------------------
// <copyright file="GvrBuildProcessor.cs" company="Google Inc.">
// Copyright 2017 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
//-----------------------------------------------------------------------

// Only invoke custom build processor when building for Android or iOS.
#if UNITY_ANDROID || UNITY_IOS

#if UNITY_IOS
using System.IO;
#endif
using System.Linq;

using UnityEditor;
using UnityEditor.Build;
#if UNITY_2018_1_OR_NEWER
using UnityEditor.Build.Reporting;
#endif
#if UNITY_IOS
using UnityEditor.iOS.Xcode;
#endif

using UnityEngine;
#if UNITY_2017_2_OR_NEWER
using UnityEngine.XR;
#else
using XRSettings = UnityEngine.VR.VRSettings;
#endif  // UNITY_2017_2_OR_NEWER

/// <summary>
/// Notifies users if they build for Android or iOS without Cardboard or Daydream enabled.
/// </summary>
#if UNITY_2018_1_OR_NEWER
internal class GvrBuildProcessor : IPreprocessBuildWithReport, IPostprocessBuildWithReport
#else
internal class GvrBuildProcessor : IPreprocessBuild, IPostprocessBuild
#endif
{
    private const string VR_SETTINGS_NOT_ENABLED_ERROR_MESSAGE_FORMAT =
        "To use the Google VR SDK on {0}, 'Player Settings > Virtual Reality Supported' setting " +
        "must be checked.\n" +
        "Please fix this setting and rebuild your app.";

    private const string IOS_MISSING_GVR_SDK_ERROR_MESSAGE =
        "To use the Google VR SDK on iOS, 'Player Settings > Virtual Reality SDKs' must include " +
        "'Cardboard'.\n" +
        "Please fix this setting and rebuild your app.";

    private const string ANDROID_MISSING_GVR_SDK_ERROR_MESSAGE =
        "To use the Google VR SDK on Android, 'Player Settings > Virtual Reality SDKs' must " +
        "include 'Daydream' or 'Cardboard'.\n" +
        "Please fix this setting and rebuild your app.";

    /// @cond
    /// <summary>Gets this `IOrderedCallback`'s callback order.</summary>
    /// <remarks>Determines which order this runs in relative to other preoprocessors.</remarks>
    /// <returns>The ordered callback step this runs in.</returns>
    public int callbackOrder
    {
        get { return 0; }
    }

    /// @endcond
#if UNITY_2018_1_OR_NEWER
    /// @cond
    /// <summary>An `IPreprocessBuildWithReport` builtin.</summary>
    /// <remarks>
    /// Implement this function to receive a callback before the build is started.
    /// </remarks>
    /// <param name="report">
    /// A report containing information about the build, such as its target platform and output
    /// path.
    /// </param>
    public void OnPreprocessBuild(BuildReport report)
    {
          OnPreprocessBuild(report.summary.platform, report.summary.outputPath);
    }

    /// @endcond
#endif

    /// @cond
    /// <summary>An `IPreprocessBuildWithReport` builtin.</summary>
    /// <remarks>
    /// Implement this function to receive a callback before the build is started.
    /// </remarks>
    /// <param name="target">The build target (Android or iOS).</param>
    /// <param name="path">This parameter is unused.</param>
    public void OnPreprocessBuild(BuildTarget target, string path)
    {
        if (target != BuildTarget.Android && target != BuildTarget.iOS)
        {
            // Do nothing when not building for Android or iOS.
            return;
        }

        // 'Player Settings > Virtual Reality Supported' must be enabled.
        if (!IsVRSupportEnabled())
        {
            Debug.LogWarningFormat(VR_SETTINGS_NOT_ENABLED_ERROR_MESSAGE_FORMAT, target);
        }

        if (target == BuildTarget.Android)
        {
            // When building for Android at least one VR SDK must be included.
            // For Google VR valid VR SDKs are 'Daydream' and/or 'Cardboard'.
            if (!IsSDKOtherThanNoneIncluded())
            {
                Debug.LogWarning(ANDROID_MISSING_GVR_SDK_ERROR_MESSAGE);
            }
        }

        if (target == BuildTarget.iOS)
        {
            // When building for iOS at least one VR SDK must be included.
            // For Google VR only 'Cardboard' is supported.
            if (!IsSDKOtherThanNoneIncluded())
            {
                Debug.LogWarning(IOS_MISSING_GVR_SDK_ERROR_MESSAGE);
            }
        }
    }

    /// @endcond
#if UNITY_2018_1_OR_NEWER
    /// @cond
    /// <summary>An `IPostprocessBuildWithReport` builtin.</summary>
    /// <remarks>
    /// Implement this function to receive a callback after the build is complete.
    /// </remarks>
    /// <param name="report">
    /// A report containing information about the build, such as its target platform and output
    /// path.
    /// </param>
    public void OnPostprocessBuild(BuildReport report)
    {
        OnPostprocessBuild(report.summary.platform, report.summary.outputPath);
    }

    /// @endcond
#endif

    /// @cond
    /// <summary>An `IPostprocessBuildWithReport` builtin.</summary>
    /// <remarks>
    /// Implement this function to receive a callback after the build is complete.
    /// </remarks>
    /// <param name="target">The build target (Android or iOS).</param>
    /// <param name="outputPath">The path to a plist file to write to.</param>
    public void OnPostprocessBuild(BuildTarget target, string outputPath)
    {
#if UNITY_IOS
        // Add Camera usage description for scanning viewer QR codes on iOS.
        if (target == BuildTarget.iOS)
        {
            // Read plist
            var plistPath = Path.Combine(outputPath, "Info.plist");
            var plist = new PlistDocument();
            plist.ReadFromFile(plistPath);

            // Update value
            PlistElementDict rootDict = plist.root;
            rootDict.SetString("NSCameraUsageDescription", "Scan Cardboard viewer QR code");

            // Write plist
            File.WriteAllText(plistPath, plist.WriteToString());
        }
#endif
    }

    /// @endcond
    /// <summary>
    /// Gets whether 'Player Settings > Virtual Reality Supported' is enabled.
    /// </summary>
    /// <returns>
    /// True if 'Player Settings > Virtual Reality Supported' is enabled.  False otherwise.
    /// </returns>
    private bool IsVRSupportEnabled()
    {
        return PlayerSettings.virtualRealitySupported;
    }

    // 'Player Settings > Virtual Reality SDKs' includes any VR SDK other than 'None'?
    private bool IsSDKOtherThanNoneIncluded()
    {
        bool containsNone = XRSettings.supportedDevices.Contains(GvrSettings.VR_SDK_NONE);
        int numSdks = XRSettings.supportedDevices.Length;
        return containsNone ? numSdks > 1 : numSdks > 0;
    }
}
#endif  // UNITY_ANDROID || UNITY_IOS
